<!-- eslint-disable -->
<template>
  <div id="main">
    <div class="head">
      <div class="logo"></div>
      <div class="title">
        <img :src="titleImg" alt="" />
        <div class="subTitle">
          <p ref="subTitle">{{ avtiveTitle }}</p>
        </div>
      </div>
    </div>
    <div class="siginList">
      <!-- <div @click="play('测试语音，我爱你')">点击11111</div> -->
      <div class="itemBox">
        <div class="item" v-for="item in list" :key="item.id">
          <div class="avatar">
            <div
              class="avatar1"
              :style="{ backgroundImage: `url(${item.headImg})` }"
            ></div>
            <div
              class="avatar2"
              :style="{
                backgroundImage: `url(${computeLevelColor(item).levelAvatar})`
              }"
            ></div>
          </div>
          <div
            class="bottom"
            :style="{ background: computeLevelColor(item).color }"
          >
            <p class="name">{{ item.userName }}</p>
            <p class="level">{{ item.bigLevelName }}</p>
          </div>
        </div>
      </div>
    </div>
    <div class="siginAni" v-show="visible">
      <div class="container">
        <div :class="['currentCls',computeLevelColor(this.soundList[this.currentIndex])?.cls]">
          <div class="box">
						<div class="avatar">
							<div
								class="avatar1"
								:style="{
									backgroundImage: `url(${
										this.soundList[this.currentIndex]?.headImg
									})`
								}"
							></div>
							<div
								class="avatar2"
								:style="{
									backgroundImage: `url(${
										computeLevelColor(this.soundList[this.currentIndex])
											?.levelAvatar
									})`
								}"
							></div>
          </div>
						<div
							class="bottom"
						>
							<p class="name">
								{{ this.soundList[this.currentIndex]?.userName }}
							</p>
							<p class="level">
								{{ this.soundList[this.currentIndex]?.bigLevelName }}
							</p>
						</div>
					</div>
        </div>
      </div>
    </div>
    <div class="aduio" @click="visibleAduio">
      <div class="screenfull"></div>
      <img :src="isMute ? voiceClose : voiceOpen" alt="" />
    </div>
    <div :class="['screenfull', isFullscreen ?'active':'unactive']" @click="toScreen"></div>
  </div>
</template>

<script>
import request from './axios'
import { getQueryParams } from './utils/common'
import ttsRecorder from './utils/tts-recorder'
import { playAideo } from './utils/websocket-media.js'
import { Fireworks } from 'fireworks-js'
import lvOption from './utils/lvOption.js'
import screenfull from 'screenfull'
export default {
  name: 'App',
  data() {
    return {
      hasSigninList: [],
      activityId: getQueryParams().activityId,
      timestamp: new Date().getTime(),
      wsUrl: `${process.env.VUE_APP_BASE_URL_WS}/screen/${
        getQueryParams().activityId
      }/`,
      avtiveTitle: '',
      titleImg: require('./assets/text@2x.png'),
      lv1: require('./assets/lv1.png'), // 会员等级头像框
      lv2: require('./assets/lv2.png'),
      lv3: require('./assets/lv3.png'),
      lv4: require('./assets/lv4.png'),
      voiceClose: require('./assets/voiceClose.svg'),
      voiceOpen: require('./assets/voiceOpen.svg'),
      socket: null, // websocket
      soundList: [], // 待播报语音队列
      currentIndex: 0, // 当前播放消息的数据
      timer: null, // websocket失败隔3s发送重新连接
      timer1: null, // 心跳检测 3s一次，6s没响应会发起重连
      errorConnectTime: 0, // 失败链接次数
      successLastTime: new Date().getTime(),
      visible: false,
      fireworks: null, // 烟花动画js
      isMute: true, // 是否静音
      isSystemClose: true,
      isFullscreen: false
    }
  },
  mounted() {
    // console.log('this.activityId: ', this.activityId)
    if (!this.activityId) {
      alert('活动id获取失败,请确认活动网址正确')
      return
    }
    this.getHasSignList()
    const container = document.querySelector('.container')
    this.fireworks = new Fireworks(container, {})
    screenfull.on("change", () => {
      this.isFullscreen = screenfull.isFullscreen;
    })
  },
  computed: {
    list() {
      const blackList = []
      const goldList = []
      const redList = []
      const blueList = []
      this.hasSigninList.forEach((one) => {
        if (one.bigLevel === 'BlackDiamond') {
          blackList.push(one)
        }
        if (one.bigLevel === 'GoldDiamond') {
          goldList.push(one)
        }
        if (one.bigLevel === 'RedDiamond') {
          redList.push(one)
        }
        if (one.bigLevel === 'BlueDiamond') {
          blueList.push(one)
        }
      })
      return [...blackList, ...goldList, ...redList, ...blueList]
    }
  },
  methods: {
    visibleAduio() {
      this.isMute = !this.isMute
    },
    toScreen(){
      screenfull.toggle()
    },
    // 计算会员颜色
    computeLevelColor(item) {
      if (!item) return
      if (item.bigLevel === 'BlackDiamond') {
        return {
          levelAvatar: this.lv1,
          color: '#FDDD8A',
          cls:'black'
        }
      } else if (item.bigLevel === 'GoldDiamond') {
        return {
          levelAvatar: this.lv2,
          color: '#F9F2B5',
          cls:'gold'
        }
      } else if (item.bigLevel === 'RedDiamond') {
        return {
          levelAvatar: this.lv3,
          color: '#FFE3E3',
          cls:'red'
        }
      } else {
        return {
          levelAvatar: this.lv4,
          color: '#ECF2FF',
          cls:'blue'
        }
      }
    },
    getHasSignList() {
      request
        .post('/screen/init', { activityId: this.activityId })
        .then((res) => {
          if (!res.data) {
            alert(res?.msg || '活动不存在或已结束')
            return
          }
          // 获取完成之后再去链接websocket。
          this.initWebSocket()
          this.avtiveTitle = res?.data?.title || '' // 活动名称
          this.hasSigninList = res?.data?.signInList || [] // 已签到列表
          this.$nextTick(() => {
            // 判断标题的长度然后决定是否滚动
            const node = this.$refs.subTitle
            const width = node.offsetWidth
            if (width > window.innerWidth * 0.7) {
              // 添加循环滚动动画
              node.className = 'ani'
            }
          })
        }).catch(err=>{
          console.log('err--->',err);
        })
    },
    initWebSocket() {
      // console.log('wsUrl333: ', this.wsUrl)
      // 心跳检测和失败重连机制清空。
      clearInterval(this.timer)
      this.timer = null
      clearInterval(this.timer1)
      this.timer1 = null
      // 发起websocket请求的时间戳
      const nowTimeNum = new Date().getTime()
      this.socket = new WebSocket(`${this.wsUrl}${nowTimeNum}`)
      this.socket.onopen = () => {
        console.log('WebSocket connection opened.')
        // 连接正常，防止重复链接
        clearTimeout(this.timer1)
        this.timer1 = null
        this.errorConnectTime = 0
        // 心跳检测 每6s给服务器发送消息，有回应了继续发，没回应了发起重连 每次调试的时候需要将下边代码注释，
        this.timer = setInterval(() => {
          const nowTime = new Date().getTime()
          if (nowTime - this.successLastTime > 20000) {
            // websocket的心跳检测20秒钟没有响应(距上一次连接成功开始算)，链接失败，重新发起链接
            clearInterval(this.timer)
            this.timer = null
            console.error('心跳检测失败,链接异常，待重新发起链接')
            this.isSystemClose = false
            this.socket.close()
            this.socket = null
            // 关闭之后会触发socket函数，会再次发起连接请求
            return
          }
          this.socket.send(
            JSON.stringify({
              activityId: this.activityId,
              timestamp: nowTimeNum // 发起ws的请求时间，这个时间需要和发起的时候时间保持一致
            })
          )
        }, 6000)
      }
      this.socket.onclose = () => {
        console.log('关闭了websocket')
        if (this.isSystemClose) {
          // 如果是系统自动关闭ws，则再尝试连接10次
          if (this.errorConnectTime > 10) {
            // 失败次数大于十次则不再进行链接
            clearInterval(this.timer1)
            this.timer1 = null
            alert('网络连接异常，请刷新页面重试')
            location.reload()
            return
          }
          this.timer1 = setTimeout(() => {
            // 链接失败后3秒重新发起请求
            this.errorConnectTime++
            this.initWebSocket()
          }, 3000)
        } else {
          // 手动关闭，需要重新发起请求
          this.initWebSocket()
        }
        this.isSystemClose = true
      }
      this.socket.onmessage = (event) => {
        this.successLastTime = new Date().getTime() // 每次收到消息更新一下最新收到消息的时间，供心跳检测使用
        const data = JSON.parse(event.data)
        if (data?.data?.length) {
          console.log('websocket发送至前端的信息:: ', data)
          this.soundList = [...this.soundList, ...data.data]
        } else {
          // 心跳检测成功
          console.log('心跳检测成功,链接正常')
        }
      }
      this.socket.onerror = (error) => {
        console.error('WebSocket error:', error)
      }
    },
    // 不同会员，不同模式下的动画效果方法
    signinAnimeFun() {
      if (
        (ttsRecorder.status === 'play' || ttsRecorder.status === 'ttsing') &&
        !this.isMute
      ) {
        console.log('当前正在播放或静音了，暂时不播放语音')
        return
      } else {
        const currentObj = this.soundList[this.currentIndex]
        // console.log('current: ', current)
        if (!currentObj) return // 没有下一个签到人员，直接结束
        if (this.visible) return // 当前动画未结束，直接return
        const itemCurr = document.querySelector('.container .currentCls')
        const text = `尊敬的德高${currentObj.bigLevelName}${currentObj.userName}，${this.avtiveTitle}会员会。欢迎您的到来！`
				this.fireworks.updateOptions(lvOption[currentObj.bigLevel] || {})
        this.visible = true
        this.$nextTick(() => {
          // 控制canvas的宽高 实现限制烟花范围
          const container = document.querySelector('.container')
          setTimeout(() => {
            itemCurr.style.scale = 1
          }, 1)
          this.fireworks.clear()
          // 不同等级的canvas画布大小不一致，需求是这么定的
          if (currentObj.bigLevel === 'BlackDiamond') {
            container.style.width = '100vw'
            this.fireworks.updateSize()
          } else if (currentObj.bigLevel === 'GoldDiamond') {
            container.style.width = '70vw'
            this.fireworks.updateSize()
          } else if (currentObj.bigLevel === 'RedDiamond') {
            container.style.width = '60vw'
            this.fireworks.updateSize()
          } else {
            container.style.width = '50vw'
            this.fireworks.updateSize()
          }
          if (currentObj.bigLevel !== 'BlueDiamond') {
            this.fireworks.start()
          }
          if (this.isMute) {
            console.log('静音模式播放')
            // 静音模式，直接播放动画， 3s后自动播放下一个
            setTimeout(() => {
              this.playNext(currentObj)
            }, 3000)
          } else {
            // 播放声音模式
            console.log('播放声音模式')
            playAideo(text, () => {
              console.log('语音播完了，播下一个')
              this.playNext(currentObj)
            })
          }
        })
      }
    },
    playNext(currentObj) {
      // 让签到的画面缩小为0 动画时间为800ms
      const itemCurr = document.querySelector('.container .currentCls')
      itemCurr.style.scale = 0
      // 烟花停止 清除
      this.fireworks.stop()
      this.fireworks.clear()
      let timer3 = setTimeout(() => {
        // 延时0.8秒去执行关闭动画，0.8之后再去播放下一个动画
        this.visible = false
        this.hasSigninList.push(currentObj)
        this.currentIndex++
        clearTimeout(timer3)
        timer3 = null
      }, 800)
    }
  },
  watch: {
    soundList: function () {
      // 有新人签到，去执行动画
      this.signinAnimeFun()
    },
    currentIndex: function () {
      // 需要播放下一个签到人了
      this.signinAnimeFun()
    }
  }
}
</script>

<style scoped lang="scss">
@keyframes Marquee {
  0% {
    transform: translate(0, 0);
  } /* 初始位置 */
  100% {
    transform: translate(-100%, 0);
  } /* 结束位置 */
}
#main {
  background: #7c070a;
  width: 100vw;
  height: 100vh;
  overflow-x: hidden;
  overflow-y: hidden;
  background-image: url(./assets/bg@2x.png);
  background-repeat: no-repeat;
  background-size: 100% 100%;
  .head {
    padding-bottom: 45px;
    position: relative;
    display: flex;
    justify-content: center;

    .logo {
      background-image: url(./assets/logo@2x.png);
      background-repeat: no-repeat;
      background-size: 100%;
      width: 157px;
      height: 95px;
      position: absolute;
      left: 57px;
      top: 34px;
    }
    .title {
      text-align: center;
      img {
        margin-top: 44px;
        width: 29.166vw;
      }
      .subTitle {
        color: #fff5e5;
        font-family: Alimama ShuHeiTi;
        font-size: 72px;
        text-shadow: 2px 2px 6px #99131a;
        overflow: hidden;
        text-align: center;
        max-width: 80vw;
        white-space: nowrap; /* 防止文字换行 */
        p {
          display: inline-block; /* 将文本设置为内联块，使其可以水平滚动 */
        }
        p.ani {
          padding-left: 100%; /* 从右侧开始滚动 */
          animation: Marquee 5s linear infinite; /* 应用动画 */
        }
      }
    }
  }
  .siginList {
    display: flex;
    flex-wrap: wrap;
    padding: 0 4vw;
    height: calc(100vh - 350px);
    overflow-x: hidden;
    overflow-y: auto;
    justify-content: center;
    &::-webkit-scrollbar {
      display: none;
    }
  }
  .siginAni {
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    margin: auto;
    opacity: 1;
    width: 100vw;
    height: 100vh;
    z-index: 99;
    background: rgba(0, 0, 0, 0.4);
    .container {
      position: absolute;
      left: 0;
      top: 0;
      bottom: 0;
      right: 0;
      height: 100vh;
      margin: auto;
			.currentCls {
				display: flex;
				align-items: center;
				justify-content: center;
				width: 500px;
				height: 500px;
				margin: 0 12px 24px 12px;
				text-align: center;
				position: absolute;
				left: 0;
				right: 0;
				top: calc(50vh - 250px);
				margin: auto;
				transition: all 0.8s ease;
				scale: 0;
				padding:100px 50;
				background-size: 100% 100%;
				background-repeat: no-repeat;
				&.black{
					background-image: url(./assets/blackBg.png);
				}
				&.gold{
					background-image: url(./assets/goldBg.png);
				}
				&.red{
					background-image: url(./assets/redBg.png);
				}
				&.blue{
					background-image: url(./assets/blueBg.png);
				}
				.box{
					width: 150px;
					height: 240px;
					position: absolute;
					left: 175px;
					top: 140px;
				}
				.avatar {
					width: 150px;
					height: 150px;
					display: flex;
					justify-content: center;
					align-items: center;
					background-position: 0 0;
					background-repeat: no-repeat;
					background-size: 100%;
					position: relative;
					.avatar1 {
						width: 120px;
						height: 120px;
						border-radius: 50%;
						overflow: hidden;
						background-position: 0 0;
						background-repeat: no-repeat;
						background-size: 100%;
						position: absolute;
						z-index: 9;
					}
					.avatar2 {
						width: 150px;
						height: 150px;
						background-position: 0 0;
						background-repeat: no-repeat;
						background-size: 100%;
						position: absolute;
						z-index: 99;
					}
				}
				.bottom {
					position: absolute;
					width: 100%;
					bottom: 8px;
					.name {
						font-size: 20px;
						color: #000000;
						display: block;
						text-overflow: ellipsis;
						overflow: hidden;
						white-space: nowrap;
					}
					.level {
						font-size: 15px;
						color: #000000;
						margin-top: 8px;
						padding-bottom: 6px;
					}
				}
			}
    }
  }
  .item {
    display: inline-block;
    width: 136px;
    margin: 0 12px 24px 12px;
    text-align: center;
    .avatar {
      width: 128px;
      height: 128px;
      padding: 4px;
      background: #ffffff;
      display: flex;
      justify-content: center;
      align-items: center;
      background-position: 0 0;
      background-repeat: no-repeat;
      background-size: 100%;
      position: relative;
      .avatar1 {
        width: 98px;
        height: 98px;
        border-radius: 50%;
        overflow: hidden;
        background-position: 0 0;
        background-repeat: no-repeat;
        background-size: 100%;
        position: absolute;
        z-index: 9;
      }
      .avatar2 {
        width: 128px;
        height: 128px;
        background-position: 0 0;
        background-repeat: no-repeat;
        background-size: 100%;
        position: absolute;
        z-index: 99;
      }
    }
    .bottom {
      .name {
        font-size: 20px;
        color: #000000;
        padding: 6px 6px 0 6px;
        display: block;
        text-overflow: ellipsis;
        overflow: hidden;
        white-space: nowrap;
      }
      .level {
        font-size: 15px;
        color: #000000;
        margin-top: 3px;
        padding-bottom: 6px;
      }
    }
  }
  .aduio {
    // 喇叭标志
    width: 30px;
    height: 30px;
    cursor: pointer;
    position: fixed;
    right: 30px;
    top: 30px;
    // background: #99131a;
    z-index: 999;
    img {
      font-size: 0;
      width: 100%;
      height: 100%;
    }
  }
  .screenfull {
    // 喇叭标志
    width: 40px;
    height: 40px;
    cursor: pointer;
    position: fixed;
    right: 72px;
    top: 25px;
    z-index: 999;
    background-size: 100% 100%;
    background-repeat: no-repeat;
    &.active {
      background-image: url(./assets/screen-narrow.svg);
    }
    &.unactive {
      background-image: url(./assets/bx-fullscreen.svg);
    }
  }
}
</style>
